﻿using Basic.Cluster.Abstract;
using Basic.Cluster.Manager;
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Basic.Cluster.Impl;

public sealed class ConsulRegister : IRegister
{
    private ConsulClient _client = null;
    private ClusterConfig _config = null;

    /// <summary>
    /// 添加服务注册
    /// </summary>
    /// <param name="services"></param>
    /// <param name="config"></param>
    /// <returns></returns>
    public IServiceCollection AddRegister(IServiceCollection services, ClusterConfig config)
    {
        _config = config;
        _client = new ConsulClient(s => { s.Address = new Uri(config.ClusterManagerAddress); });

        services.AddSingleton<ClusterConfig>(_config);
        services.AddSingleton<ConsulClient>(_client);
        services.AddHealthChecks();

        var discover = new ConsulDiscover();
        discover.AddRegister(_client);
        services.AddSingleton<IDiscover>(discover);

        return services;
    }

    /// <summary>
    /// 启动服务注册
    /// </summary>
    /// <param name="app"></param>
    /// <returns></returns>
    public IApplicationBuilder UseRegister(IApplicationBuilder app)
    {
        var consulClient = _client;
        var confInfo = _config;
        app.UseHealthChecks("/health");

        var registration = CreateRegistration(confInfo);

        // 获取主机生命周期对象
        var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
        lifetime.ApplicationStarted.Register(async () =>
        {
            _ = await consulClient.Agent.ServiceRegister(registration);
        });
        lifetime.ApplicationStopping.Register(async () =>
        {
            _ = await consulClient.Agent.ServiceDeregister(registration.ID);
        });

        return app;
    }

    /// <summary>
    /// 创建http服务注册信息对象
    /// </summary>
    /// <param name="confInfo"></param>
    /// <returns></returns>
    private AgentServiceRegistration CreateRegistration(ClusterConfig confInfo)
    {
        AgentServiceCheck check = new AgentServiceCheck
        {
            CheckID = confInfo.ID,
            HTTP = confInfo.HealthCheck,
            Interval = TimeSpan.FromSeconds(confInfo.HealthInterval ?? 30),
            Timeout = TimeSpan.FromSeconds(confInfo.HealthInterval ?? 5),
            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(2),
        };
        return new AgentServiceRegistration()
        {
            Check = check,
            ID = confInfo.ID,
            Name = confInfo.Name,
            Address = confInfo.IP,
            Port = confInfo.Port,
            Meta = confInfo.ServiceMeta,
        };
    }

}